package xwebsocket

import (
	"net/http"

	"gitee.com/lihaiping1603/utils/log"
	"github.com/gorilla/websocket"
)

//--------------------------------------------------------------------------------------------------------------------------
// 为什么HTTP协议和WS协议可以复用同一端口:
// 在客户端发起websocket连接时，客户端会向浏览器发送一个http请求，该请求的请求头包含Connection:Upgrade和Upgrade:websocket，向服务器请求修改协议为websocket，
// 如果服务器同意修改协议，则会响应一个响应码为101的HTTP报文，至此HTTP的职责已经完成，下面的通讯则会采用websocket协议。
//（注意：只有在客户端使用实例化的websocket实例传输数据才会采用websocket协议，在此期间客户端仍可以发起其他的http请求，两者并不冲突）。
//
//​ 由此可得，只需让http服务处理所有的请求，在遇到Connection:Upgrade和Upgrade:websocket时换用websocket服务即可，
// 此时只需http监听端口，而websocket不必对外监听，而由http服务直接转发。
//---------------------------------------------------------------------------------------------------------------------------

func TryWebsocketUpgrade(w http.ResponseWriter, r *http.Request, wshandler WebsocketHandler, httphandler http.Handler) {
	if !websocket.IsWebSocketUpgrade(r) {
		httphandler.ServeHTTP(w, r)
		return
	}
	WebsocketUpgrade(w, r, wshandler)
}

func WebsocketUpgrade(w http.ResponseWriter, r *http.Request, wshandler WebsocketHandler) (*WebsocketSession, error) {
	upgrader := websocket.Upgrader{
		// 允许跨域
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	} // use default options
	//upgrader.Upgrade函数里面会对http的头部字段进行判断，如果是websocket的协议发过来的链接的话，请求头部会包含Connection:Upgrade和Upgrade:websocket
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Warn("websocket conn %s upgrade failed: %s", r.RemoteAddr, err)
		return nil, err
	}
	session := smgr.newWebsocketSession(conn, wshandler)
	session.header = r.Header
	session.uri = r.RequestURI
	if wshandler != nil {
		if err = wshandler.OnConnected(session); err != nil {
			session.Close()
			return nil, err
		}
	}
	go session.readCycle()
	return session, nil
}
